<template>
	<div class="imgage-container"  v-loading="loading">
		<el-upload class="avatar-uploader" action="" :http-request="doUpload" :accept="accept_type" :multiple="multiple"
		 :drag="drag" :list-type="listType" :auto-upload="autoUpload" :show-file-list="showFileList" :file-list="fileList"
		 :before-upload="beforeUpload" :on-preview="onPreview" :on-remove="onRemove" :on-success="onSuccess" :on-on-error="onError"
		 :on-progress="onProgress" :on-change="onChange" :before-remove="beforeRemove" :on-exceed="onExceed" >
		 	<slot v-if="$slots.default"></slot>
			<template v-else-if="url && (uploadType == 'image' || uploadType == 'video')">
				<div :style="{'width':buttonWidth+'px','height':buttonHeight+'px'}">
					<el-image v-if="uploadType == 'image'" :src="url" class="avatar" fit="fill" ></el-image>
					<video v-else-if="uploadType == 'video'" :src="url"></video>
				</div>
			</template>
			<template v-else>
				<div class="lx-upload-button" :style="{'width':buttonWidth+'px','height':buttonHeight+'px'}">
					<i class="el-icon-plus avatar-uploader-icon"></i>
					<div class="avatar-uploader-text">{{button_name}}</div>
				</div>
			</template>
			<div slot="tip" class="el-upload__tip" v-if="tipContent">
				<span>{{tipContent}}</span>
			</div>
			
			<!-- 进度条还没做好 主要是没想好怎么放-->
			<el-progress v-if="isFrag" :percentage="progressNum" :show-text="false"></el-progress>
		</el-upload>
	</div>
</template>

<script>
	import md5 from 'js-md5'
	export default {
		props: {
			that: {
				type: Object,
				default: this
			},
			multiple: {
				type: Boolean,
				default: false
			},
			drag: {
				type: Boolean,
				default: false
			},
			autoUpload: {
				type: Boolean,
				default: true
			},
			uploadType: {
				//image,video,file
				type: String,
				default: "image"
			},
			buttonName: {
				type: String,
				default: ""
			},
			buttonWidth:{
				type:Number,
				default:120
			},
			buttonHeight:{
				type:Number,
				default:120
			},
			acceptType: {
				type: String,
				default: ""
			},
			tipContent: {
				type: String,
				default: ""
			},
			maxFileSize: {
				// 单位M
				type: Number,
				default: 0
			},
			fileNum: {
				type: Number,
				default: 1
			},
			showFileList: {
				type: Boolean,
				default: false
			},
			listType: {
				//text/picture/picture-card
				type: String,
				default: "text"
			},
			validate: {
				type: Function,
				default: () => {
					return false;
				}
			},
			defaultUrl: {
				type: String,
				default: ""
			},
			uploadFunction: {
				type: String,
				default: "photoUpload"//默认是图片上传
			},
			uploadParam: {
				type: Object,
				default: () => {}
			},
			isFrag: {
				type: Boolean,
				default: false
			},
			pieceSize:{
				type:Number,
				default:2//默认2M
			}
		},
		mounted() {
			let button_name;
			let accept_type;
			let max_file_size;
			switch (this.uploadType) {
				case "video":
					button_name = this.buttonName || "上传视频";
					accept_type = this.acceptType || "video/*";
					max_file_size = this.maxFileSize || 200;
					break;
				case "file":
					button_name = this.buttonName || "上传文件";
					accept_type = this.acceptType || "*";
					max_file_size = this.maxFileSize || 50;
					break;
				case "image":
				default:
					accept_type = this.acceptType || "image/*";
					button_name = this.buttonName || "上传图片";
					max_file_size = this.maxFileSize || 10;
					break;
			}
			this.max_file_size = max_file_size;
			this.button_name = button_name;
			this.accept_type = accept_type;
			if (this.defaultUrl) {
				this.url = this.defaultUrl;
			} else {
				this.url = "";
			}
			this.uploadList = [];
		},
		watch: {
			defaultUrl() {
				if (this.defaultUrl) {
					this.url = this.defaultUrl;
				} else {
					this.url = "";
				}
				this.uploadList = [];
			}
		},
		data() {
			return {
				loading:false,
				url: "",
				accept_type: "",
				button_name: "",
				tip_content: "",
				max_file_size: 10,
				uploadList: [],
				fileList: [],
				/*分片上传*/
				progressNum: 0, // 进度
				currentChunk:0,
				successAllCount: 0, // 上传成功的片数
				currentAllChunk: 0, // 当前上传的片数索引
				AllChunk: 0, // 所有文件的chunk数之和
				AllFileSize: 0, // 所有文件size
				terminateUpload:false
			}
		},
		methods: {
			doUpload(params) {
				let url;
				if(this.isFrag){
					this.doFragUpload(params);
				}else{
					this.doNormal(params)
				}
				this.$emit("doUpload", url);
			},
			async doNormal(params){
				let _this = this;
				_this.loading = true;
				let file = params.file;
				let fileType = file.type;
				let fileName = file.name;
				let fileExtension = fileName.substr(fileName.lastIndexOf(".") + 1, fileName.length);
				let formData = new FormData();
				formData.append('fileExtension', fileExtension);
				formData.append('file', file);
				let uploadParam = _this.uploadParam;
				if (uploadParam && JSON.stringify(uploadParam) != "{}") {
					for (pName in uploadParam) {
						formData[pName] = uploadParam[pName];
					}
				}
				let ret = await _this.$api[_this.uploadFunction](formData);
				
				if (ret) {
					_this.fileList.push(file);
					let url = ret.fileUrl;
					_this.url = url;
					_this.uploadList.push(url);
					file.url = url;
					_this.$emit("onSuccess", null, file, _this.fileList);
				}
				_this.loading = false;
			},
			beforeUpload(file) {
				if (this.validate()) {

				} else {

					if (this.uploadType == "image") {
						const isRightFile = file.type.startsWith("image");
						if (!isRightFile) {
							this.$message.error('只能上传图片!');
							return false;
						}
					} else if (this.uploadType == "video") {
						const isRightFile = file.type.startsWith("video");
						if (!isRightFile) {
							this.$message.error('只能上传视频!');
							return false;
						}
					}
					const maxFileSize = this.max_file_size;
					const isRightSize = Number(file.size) / 1024 / 1024 < maxFileSize;
					if (!isRightSize) {
						this.$message.error('上传大小不能超过 ' + maxFileSize + 'MB!');
						return false;
					}


				}
				this.$emit("beforeUpload", file);
				return true;
			},
			onPreview(file) {
				//点击文件列表中已上传的文件时的钩子
				this.$emit("onPreview", file);
			},
			onRemove(file, fileList) {
				//文件列表移除文件时的钩子
				this.$emit("onPreview", file, fileList);
			},
			onSuccess(response, file, fileList) {
				//文件上传成功时的钩子
				this.$emit("onSuccess", response, file, fileList);
			},
			onError(err, file, fileList) {
				//文件上传失败时的钩子
				this.$emit("onPreview", err, file, fileList);
			},
			onProgress(event, file, fileList) {
				console.log(event);
				//文件上传时的钩子
				this.$emit("onProgress", event, file, fileList);
			},
			onChange(file, fileList) {
				//文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
				this.$emit("onChange", file, fileList);
			},
			beforeRemove(file, fileList) {
				//删除文件之前的钩子，参数为上传的文件和文件列表，若返回 false 或者返回 Promise 且被 reject，则停止删除
				this.$emit("beforeRemove", file, fileList);
			},
			onExceed(iles, fileList) {
				//文件超出个数限制时的钩子
				this.$emit("beforeRemove", file, fileList);
			},
			getUploadResult() {
				return {
					url: this.url,
					uploadList: this.uploadList
				}
			},


			/**分片上传*/
			doFragUpload(params){
				this.progressNum = 0; // 进度
				this.currentChunk= 0;
				this.successAllCount = 0; // 上传成功的片数
				this.currentAllChunk = 0; // 当前上传的片数索引
				this.AllChunk = 0; // 所有文件的chunk数之和
				this.AllFileSize = 0; // 所有文件size
				this.terminateUpload = false;
				
				let file = params.file;
				let fileType = file.type;
				let fileName = file.name;
				this.readFileMD5([file]);
			},
			// 获取md5
			readFileMD5(files) {
				// 读取每个文件的md5
				let _this = this;
				let fileList = [];
				files.map((file, index) => {
					let fileRederInstance = new FileReader()
					fileRederInstance.readAsBinaryString(file);
					fileRederInstance.onload = function(e){
						let fileBolb = e.target.result
						let fileMD5 = md5(fileBolb)
						if (!fileList.some((arr) => arr.md5 === fileMD5)) {
							fileList.push({
								fileMD5: fileMD5,
								name: file.name,
								file
							})
							_this.AllFileSize = _this.AllFileSize + file.size
						}
						if (index === files.length - 1){
							_this.readChunkMD5(fileList);
						}
					}
				})
			},
			getChunkInfo(file, chunkSize) {
				//获取分片信息
				let start = this.currentChunk * chunkSize
				let end = Math.min(file.size, start + chunkSize)
				let chunk = file.slice(start, end)
				return {start,end,chunk}
			},
			async readChunkMD5(fileList) {
				let _this = this;
				// 针对每个文件进行chunk处理
				for (let fileIndex = 0; fileIndex < fileList.length; fileList++) {
					let currentFile = fileList[fileIndex];
					const chunkSize = _this.pieceSize * 1024 * 1024 // 20MB一片
					const chunkCount = Math.ceil(currentFile.file.size / chunkSize) // 总片数
					_this.AllChunk = _this.AllChunk + chunkCount // 计算全局chunk数
					// let fileSize = currentFile.file.size // 文件大小
					// 针对单个文件进行chunk上传
					let chunkErrorCunt = 0;//单片上传
					for (let currentChunk = 0; currentChunk < chunkCount;) {
						const {	chunk} =_this.getChunkInfo(currentFile.file, currentChunk, chunkSize);
						if(_this.terminateUpload ){
							_this.$message.info("上传终止");
							//如果上传次数大于3次则说明接口有问题 终止上传
							_this.terminateUpload = false;
							break;
						}
						if(chunkErrorCunt >= 3){
							_this.$message.error("当前分片上传失败");
							break;
						}
						await _this.readChunkFile(currentFile, chunk, chunkCount, fileIndex, currentChunk).then(res => {
							let ucc = res.currentChunk;
							if(ucc == currentChunk){
								//上传后的分片索引如果等于当前索引，则说明当前上传失败
								chunkErrorCunt++;
							}else{
								chunkErrorCunt = 0;
								currentChunk = ucc;
							}
							_this.successAllCount = currentChunk;
							_this.progressFun();
							if(currentChunk == chunkCount){
								_this.progressFun();
								let url = res.data.videoUrl;
								_this.url = url;
								if(!_this.uploadList.includes(url)){
									_this.uploadList.push(url);
								}
								_this.$emit("onSuccess", res, currentFile.file, fileList);
							}
						})
					}
				}
			},
			readChunkFile(currentFile, chunk, chunkCount, fileIndex, chunkIndex) {
				let _this = this;
				//读取分片MD5信息
				return new Promise((resolve, reject) => {
					let chunkFR = new FileReader();
					chunkFR.readAsBinaryString(chunk);
					chunkFR.onload = async function(e) {
						let chunkBolb = e.target.result
						let chunkMD5 = md5(chunkBolb)
						let res = await _this.uploadChunk(currentFile, {
							chunkMD5,
							chunk,
							currentChunk: chunkIndex,
							chunkCount
						}, fileIndex);
						resolve(res);
					}
				})
			},
			async uploadChunk(currentFile, chunkInfo, fileIndex) {
				let _this = this;
				let fetchForm = new FormData()
				fetchForm.append('fileSizeTotal', currentFile.file.size)
				fetchForm.append('fileName', currentFile.name)
				fetchForm.append('fileMD5', currentFile.fileMD5)
				fetchForm.append('file', chunkInfo.chunk)
				fetchForm.append('slicesNum', chunkInfo.chunkCount)
				fetchForm.append('slicesId', chunkInfo.currentChunk)
				return await this.$api.uploadTeachVideo(fetchForm).then(res => {
					let currentChunk = 0;
					if (Number(res.errCode) == 0 && res.data) {
						let slicesIds = res.data.slicesIds; //已上传的索引
						let ids = slicesIds.split(",");
						currentChunk = Number(ids[ids.length - 1]);
					}
					res.currentChunk = currentChunk+1;
					
					return res
				}).catch((e) => {
					console.log(e)
					return {currentChunk:chunkInfo.currentChunk};
				})
			},
			progressFun(){
				this.progressNum = Math.ceil(this.successAllCount / this.AllChunk * 100)
				console.log("进度"+this.progressNum+"%")
			},
			terminate(){
				this.terminateUpload = true;
			}

		}
	}
</script>

<style lang="scss" scoped="scoped">
	.imgage-container {}

	::v-deep .avatar-uploader {
		display: flex;
		flex-direction: row;
		.lx-upload-button{
			display: flex;
			flex-direction: column;
			justify-content: center;
			align-items: center;
		}
		.el-upload {
			border-radius: 6px;
			cursor: pointer;
			position: relative;
			overflow: hidden;
			float: left;
			line-height: 14px;
			background-color: #F7F8FA;
			display: flex;
			flex-direction: column;
			justify-content: center;
			border: none;

			.avatar-uploader-icon {
				font-size: 30px;
				color: #DADEE1;
				margin-bottom: 16px;
			}

			.avatar-uploader-text {
				color: #999999;
				font-size: 14px;
			}

			.avatar {

				.el-image__inner {
				}
			}
		}

		.el-upload__tip {
			width: 0;
			flex: 1;
			font-size: 14px;
			display: flex;
			padding-left: 16px;
			color: #B2B2B2;
			flex-direction: column;
			justify-content: flex-end;
			line-height: 20px;
		}
	}
</style>
